/*
 * BufferedImageUtils
 * Common and useful utility functions involving BufferedImages.
 * All the functions are static to alleviate class instantiation.
 * Luke Mitchell 09-04-12 <lm0466@my.bristol.ac.uk>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.File;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.AffineTransform;
import javax.imageio.*;

public class BufferedImageUtils
{
    // error handling function
    private static void error (String msg)
    {
        System.err.println (msg);
    }

    // reverses an integer (pixel) array
    private static int[] reverse (int[] arr)
    {
        int[] ret = new int[arr.length];

        for (int i = 0; i < arr.length; i++)
            ret [i] = arr[arr.length - 1 - i];

        return ret;
    }
	
	// returns the dimension of the image
	public static Dimension get_dimensions (BufferedImage img)
	{
		return new Dimension (img.getWidth (), img.getHeight ());
	}

    // returns the coordinates (as a Point) of the centre of the specified image
    public static Point image_centre (BufferedImage img)
    {
        return new Point (img.getWidth () / 2, img.getHeight () / 2);
    }

    // reflects the image in the y direction
    public static BufferedImage reflect_vertical (BufferedImage img)
    {
        BufferedImage reflected;
        int height = img.getHeight (), width = img.getWidth ();
        int[] row = new int[width];

        reflected = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
        
        for (int y = 0; y < height; y++)
        {
            row = img.getRGB (0, y, width, 1, row, 0, 1);
            reflected.setRGB (0, y, width, 1, reverse (row), 0, 1);
        }

        return reflected;
    }

    // reflects the image in the x direction
    public static BufferedImage reflect_horizontal (BufferedImage img)
    {
        BufferedImage reflected;
        int height = img.getHeight (), width = img.getWidth ();

        reflected = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);

        for (int y = 0; y < height; y++)
            for (int x = 0; x < width; x++)
                reflected.setRGB (x, height - 1 - y, img.getRGB (x, y));

        return reflected;
    }

    // reflects image both in x and y
    public static BufferedImage reflect_both (BufferedImage img)
    {
        return reflect_vertical (reflect_horizontal (img));
    }

    // rotates an image through theta radians
    public static BufferedImage rotate_theta_clockwise (BufferedImage img, double theta)
    {
        double sin = Math.abs(Math.sin(theta)), cos = Math.abs(Math.cos(theta));
        int w = img.getWidth (), h = img.getHeight ();
        int neww = (int) Math.floor(w*cos+h*sin), newh = (int) Math.floor(h*cos+w*sin);

        BufferedImage rot = new BufferedImage (neww, newh, img.getColorModel ().getTransparency ());

        Graphics2D g2d = rot.createGraphics ();
        g2d.translate((neww-w)/2, (newh-h)/2);
        g2d.rotate(theta, w/2, h/2);
        g2d.drawRenderedImage(img, null);

        return rot;
    }

    // rotate the image 90 deg CW
    public static BufferedImage rotate_90_clockwise (BufferedImage img)
    {
        return rotate_theta_clockwise (img, Math.toRadians (90));
    }

    // rotate the image 90 deg CCW
    public static BufferedImage rotate_90_anticlockwise (BufferedImage img)
    {
        return rotate_theta_clockwise (img, Math.toRadians (270));
    }

    // loads an image from specified filename
    public static BufferedImage load_image (String filename)
    {
        BufferedImage img = null;

        try
        {
            img = ImageIO.read (new File (filename));
        }

        catch (Exception e)
        {
            error ("Cannot load file: " + filename);  
        }

        return img;
    }

    public static BufferedImage load_image (File file)
    {
        BufferedImage img = null;
    
        try
        {
            img = ImageIO.read (file);
        }

        catch (Exception e)
        {
            error ("Cannot load file " + file.getName());
        }

        return img;
    }

    // saves an image to specified filename
    public static void save_image (BufferedImage img, String filename, String filetype)
    {
        try
        {
            ImageIO.write (img, filetype, new File (filename));
        }

        catch (Exception e)
        {
            error ("Cannot save file: " + filename + "." + filetype);
        }
    }

    public static void save_image (BufferedImage img, File file)
    {
        String filetype = "png";

        try
        {
            ImageIO.write (img, filetype, file);
        }

        catch (Exception e)
        {
            error ("Cannot save file: " + file.getName());
        }
    }
}
